/*
 * \brief  Native part of asynchronous notification mechanism
 * \author Norman Feske
 * \date   2008-09-05
 *
 * Never include this file but rather use the platform-independent interface
 * as specified in 'base/signal.h'.
 *
 * The generic version of the signalling mechanism employs one thread at each
 * transmitter (signal-tx) and one thread at each receiver (signal-rx). The
 * signal-tx thread blocks on a wait lock and gets activated when another
 * thread submits a signal. Once activated, it performs a blocking call to the
 * receiver. During the blocking time, more signal submissions may come in,
 * which are accumulated using a counter and delivered in the next call. The
 * signal-rx thread waits for incoming signal calls and steers a semaphore,
 * which provides the interface to another thread requesting a signal via the
 * wait_for_signal function.
 *
 * Because this mechanism involves one thread for each transmitter and one
 * for each receiver, it is pretty heavy-weight. Therefore, ports of Genode
 * should replace this implementation with better native one, for example
 * by using inter-process semaphores or native kernel support for signals.
 */

/*
 * Copyright (C) 2008-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _INCLUDE__BASE__NATIVE_SIGNAL_H__
#define _INCLUDE__BASE__NATIVE_SIGNAL_H__

#include <base/semaphore.h>
#include <base/typed_capability.h>
#include <base/thread.h>
#include <base/ipc.h>
#include <cap_session/cap_session.h>

namespace Genode {

	/**
	 * Capability type for signal receiver
	 */
	class Native_signal_receiver;
	typedef Typed_capability<Native_signal_receiver> Native_signal_receiver_capability;


	class Native_signal
	{
		private:

			int _imprint;
			int _num;

			friend class Native_signal_receiver;

			/**
			 * Constructor
			 *
			 * \param imprint  imprint specific for the transmitter
			 * \param num      number of signals received from the same transmitter
			 *
			 * Signal object are constructed only by signal receivers.
			 */
			Native_signal(int imprint, int num)
			:
				_imprint(imprint),
				_num(num)
			{ }

		public:

			/**
			 * Return imprinted notification argument
			 */
			long imprint() { return _imprint; }

			/**
			 * Return number of signals received from the same transmitter
			 */
			int  num() { return _num; }
	};


	/**
	 * Generic version of a native signal transmitter
	 */
	class Native_signal_transmitter : Thread<2048>
	{
		private:

			int        _signal_cnt;         /* number of pending notifications       */
			Lock       _signal_cnt_lock;    /* protection of '_signal_cnt'           */
			Lock       _wait_lock;          /* blocking facility for delivery thread */
			Msgbuf<32> _snd_msg, _rcv_msg;  /* message buffers for signal receiver   */
			Ipc_client _receiver;           /* signal receiver                       */

			/**
			 * Deliver currently pending number of notifications to receiver
			 *
			 * This function blocks until the receiver answers the call.
			 */
			void _deliver();

			/**
			 * Delivery thread function checks for new signals and delivers them
			 */
			void entry();

		public:

			/**
			 * Constructor
			 *
			 * \param receiver  capability to signal receiver
			 */
			Native_signal_transmitter(Native_signal_receiver_capability receiver = Native_signal_receiver_capability());

			/**
			 * Set signal receiver
			 */
			void receiver(Native_signal_receiver_capability receiver);

			/**
			 * Trigger signal submission to receiver
			 */
			void submit();
	};


	/**
	 * Signal receiver
	 */
	class Native_signal_receiver : Thread<2048>
	{
		private:

			Cap_session  *_cap_session;       /* produce signal-receiver capabilities */
			Native_signal _curr_signal;       /* currently received signal            */
			bool          _pending;           /* current signal is valid              */
			Semaphore     _signal_available;  /* signal awaits to be picked up        */
			Lock          _fetch_next_lock;   /* lock for deferring next receive      */
			Lock         *_startup_lock;      /* handshake synchronization            */
			Capability    _cap;               /* handshake argument                   */

			/**
			 * Signal receiver thread waits for signals
			 */
			void entry();

		public:

			/**
			 * Constructor
			 *
			 * \param cap_session  CAP session for allocating signal-receiver capabilities
			 */
			Native_signal_receiver(Cap_session *cap_session);

			/**
			 * Return new signal-receiver capability
			 *
			 * \param imprint      argument to be delivered with each signal
			 * \return             new signal-receiver capability that can be
			 *                     passed to a signal transmitter
			 */
			Native_signal_receiver_capability cap(long imprint = 0);

			/**
			 * Return true if signal was received
			 */
			bool pending() { return _pending; }

			/**
			 * Block until a signal is received
			 *
			 * \return received signal
			 */
			Native_signal wait_for_signal();
	};
}

#endif /* _INCLUDE__BASE__NATIVE_SIGNAL_H__ */
